/* 
 * PROJECT: NyARToolkit(Extension)
 * --------------------------------------------------------------------------------
 *
 * The NyARToolkit is Java edition ARToolKit class library.
 * Copyright (C)2008-2012 Ryo Iizuka
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as publishe
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * For further information please contact.
 *	http://nyatla.jp/nyatoolkit/
 *	<airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>
 * 
 */
package jp.nyatla.nyartoolkit.core.rasterdriver.pickup;


import jp.nyatla.nyartoolkit.core.NyARRuntimeException;
import jp.nyatla.nyartoolkit.core.raster.rgb.*;
import jp.nyatla.nyartoolkit.core.raster.rgb.format.NyARRgbRaster_INT1D_X8R8G8B8_32;
import jp.nyatla.nyartoolkit.core.types.*;
import jp.nyatla.nyartoolkit.core.types.matrix.*;


/**
 * このクラスは、疑似アフィン変換を使用して画像からパターンを取得します。
 * 取得領域は、領域を定義する４頂点と、除外する枠線の幅（割合）から定義します。
 */
public class NyARColorPatt_PseudoAffine extends NyARRgbRaster_INT1D_X8R8G8B8_32 implements INyARColorPatt
{
	final private NyARDoubleMatrix44 _invmat=new NyARDoubleMatrix44();

	/**
	 * コンストラクタです。
	 * @param i_width
	 * このラスタの幅
	 * @param i_height
	 * このラスタの高さ
	 * @throws NyARRuntimeException 
	 */
	public NyARColorPatt_PseudoAffine(int i_width, int i_height)
	{
		super(i_width,i_height,true);
		//疑似アフィン変換のパラメタマトリクスを計算します。
		//長方形から計算すると、有効要素がm00,m01,m02,m03,m10,m11,m20,m23,m30になります。
		final NyARDoubleMatrix44 mat=this._invmat;
		mat.m00=0;
		mat.m01=0;
		mat.m02=0;
		mat.m03=1.0;
		mat.m10=0;
		mat.m11=i_width-1;
		mat.m12=0;
		mat.m13=1.0;
		mat.m20=(i_width-1)*(i_height-1);
		mat.m21=i_width-1;
		mat.m22=i_height-1;
		mat.m23=1.0;
		mat.m30=0;
		mat.m31=0;
		mat.m32=i_height-1;
		mat.m33=1.0;
		mat.inverse(mat);
		return;
	}	

	/**
	 * 変換行列と頂点座標から、パラメータを計算
	 * o_paramの[0..3]にはXのパラメタ、[4..7]にはYのパラメタを格納する。
	 * @param i_vertex
	 * @param pa
	 * @param pb
	 */
	private void calcPara(NyARIntPoint2d[] i_vertex,double[] o_cparam)
	{
		final NyARDoubleMatrix44 invmat=this._invmat;
		double v1,v2,v4;
		//変換行列とベクトルの積から、変換パラメタを計算する。
		v1=i_vertex[0].x;
		v2=i_vertex[1].x;
		v4=i_vertex[3].x;
		
		o_cparam[0]=invmat.m00*v1+invmat.m01*v2+invmat.m02*i_vertex[2].x+invmat.m03*v4;
		o_cparam[1]=invmat.m10*v1+invmat.m11*v2;//m12,m13は0;
		o_cparam[2]=invmat.m20*v1+invmat.m23*v4;//m21,m22は0;
		o_cparam[3]=v1;//m30は1.0で、m31,m32,m33は0
		
		v1=i_vertex[0].y;
		v2=i_vertex[1].y;
		v4=i_vertex[3].y;

		o_cparam[4]=invmat.m00*v1+invmat.m01*v2+invmat.m02*i_vertex[2].y+invmat.m03*v4;
		o_cparam[5]=invmat.m10*v1+invmat.m11*v2;//m12,m13は0;
		o_cparam[6]=invmat.m20*v1+invmat.m23*v4;//m21,m22は0;
		o_cparam[7]=v1;//m30は1.0で、m31,m32,m33は0
		return;
	}

	/**
	 * 疑似アフィン変換の変換パラメタ
	 */
	private double[] _convparam=new double[8];
	
	/**
	 * この関数は、ラスタのi_vertexsで定義される四角形からパターンを取得して、インスタンスに格納します。
	 */
	public boolean pickFromRaster(INyARRgbRaster image,NyARIntPoint2d[] i_vertexs)throws NyARRuntimeException
	{
		final double[] conv_param=this._convparam;
	    int rx2,ry2;
		rx2=this._size.w;
		ry2=this._size.h;
		int[] rgb_tmp=new int[3];

		// 変形先領域の頂点を取得

		//変換行列から現在の座標系への変換パラメタを作成
		calcPara(i_vertexs,conv_param);// 変換パラメータを求める
		for(int y=0;y<ry2;y++){
			for(int x=0;x<rx2;x++){
				final int ttx=(int)((conv_param[0]*x*y+conv_param[1]*x+conv_param[2]*y+conv_param[3])+0.5);
				final int tty=(int)((conv_param[4]*x*y+conv_param[5]*x+conv_param[6]*y+conv_param[7])+0.5);
				this.getPixel((int)ttx,(int)tty,rgb_tmp);
				this._buf[x+y*rx2]=(rgb_tmp[0]<<16)|(rgb_tmp[1]<<8)|rgb_tmp[2];				
			}
		}
		return true;
	}
	public Object createInterface(Class<?> iIid) {
		// TODO Auto-generated method stub
		return null;
	}
}